package Grammar;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * BigDecimal 解决浮点数计算精度问题
 */
public class BigDecimalTest {
    /**
     * 首先，在日常计算中，由于计算机底层的缘故
     * 在一定情况下无法正确表示所有的小数
     * 所以在浮点型计算的时候，他只能抱在在一定情况下的计算精度
     * 但是，超出这个范围的时候，则无法正确表示
     */
    public static void main1(String[] args) {
        double d1 = 0.1;
        double d2 = 0.2;

        System.out.println(d1 + d2);//此时打印的结果是0.30000000000000004
    }

    /**
     * 在金融领域，对于上述的精度问题是无法接受的
     * 为了能够正确地计算，Java实现了一个BigDecimal这个实现类
     * 他的本质是用字符数组类型来进行存储，当出现加减乘除计算的时候
     * 可以直接通过对字符数组进行每一位的计算，从而获得一个精确的数值
     */

    public static void main2(String[] args) {
        /**
         * 下面是BigDecimal常见的构造器
         */
        //public BigDecimal(double val) ，但是不推荐使用这个，这个本质上并没有解决精度问题，依旧会存在精度问题
        BigDecimal d1 = new BigDecimal(0.1);
        //public BigDecimal(String val) ，推荐使用这种，将String转成BigDecimal
        BigDecimal d2 = new BigDecimal("0.2");

        //但是在我们实际从用户端接收到的浮点型数据不会用String来进行存储，
        //所以实际在调用上述构造器的时候，本质还会调用一个转成String的方法，就会变成
        BigDecimal d3 = new BigDecimal(Double.toString(0.1));
        //所以为了使用方便，实际可以使用BigDecimal提供的valueOf方法
        //public static BigDecimal valueOf(double val)
        BigDecimal d4 = BigDecimal.valueOf(0.1);

    }

    /**
     * BigDecimal常见方法
     */
    public static void main(String[] args) {
        BigDecimal d4 = BigDecimal.valueOf(0.1);
        BigDecimal d5 = BigDecimal.valueOf(0.2);
        //加法 public BigDecimal add(BigDecimal b)
        System.out.println(d4.add(d5));
        //减法 public BigDecimal subtract(BigDecimal b)
        System.out.println(d4.subtract(d5));
        //乘法 public BigDecimal multiply(BigDecimal b)
        System.out.println(d4.multiply(d5));
        //除法 public BigDecimal divide(BigDecimal b)
        System.out.println(d4.divide(d5));

        /**
         * 此时需要注意，当出现无法整除的情况时，如果不给出精度范围，会出现错误
         */
        BigDecimal d6 = BigDecimal.valueOf(0.3);
//        System.out.println(d4.divide(d6));//此时会爆出java.lang.ArithmeticException异常
        //为了解决上述情况，除法无法整除时，必须规定精度
        //除法 public BigDecimal divide(BigDecimal b,精确几位，舍位模式)
        System.out.println(d5.divide(d6,5, RoundingMode.HALF_UP));

        //将BigDecimal转换为double
        //public double doubleValue()
        double d7 = d4.divide(d6,5, RoundingMode.HALF_UP).doubleValue();
    }
}
